import json
import os
import time
import traceback

from PyQt5.QtCore import pyqtSignal, QObject, pyqtSlot, Qt
from PyQt5.QtWebChannel import QWebChannel
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QLabel, QMessageBox)

from style_manager import StyleManager  # 添加到文件顶部


class WebBridge(QObject):
    """JavaScript桥接类，用于处理从JavaScript到Python的回调"""

    def __init__(self, parent=None, web_page=None):
        super().__init__(parent)
        self.parent = parent
        self.web_page = web_page  # 初始化web_page属性

    @pyqtSlot(str)
    def contentChanged(self, content_json):
        """处理内容变化的JavaScript回调"""
        try:
            content = json.loads(content_json)
            self.parent.handle_content_change(content)
        except Exception as e:
            self.parent.log_message(f"内容解析错误: {str(e)}", 'ERROR')

    @pyqtSlot(str)
    def handleEnterKey(self, position_info):
        """处理Enter键的JavaScript回调"""
        self.parent.log_message(f"收到Enter键事件，原始位置信息: {position_info}", 'DEBUG')
        try:
            info = json.loads(position_info)
            # 调用父对象的分割行方法
            self.parent.split_line(info)
        except Exception as e:
            self.parent.log_message(f" 处理Enter键事件错误: {str(e)}", 'ERROR')
            self.parent.log_message(traceback.format_exc(), 'ERROR')

    @pyqtSlot(str)
    def handleBackspaceKey(self, positionInfo):
        """处理Backspace键的JavaScript回调
        Args:
            positionInfo: JSON字符串，包含光标位置等信息
        """
        self.parent.log_message(f"收到Backspace键事件: {positionInfo}", 'DEBUG')
        try:
            data = json.loads(positionInfo)
            # 获取当前选择状态
            # self.web_page.runJavaScript("""
            #     (function() {
            #         try {
            #             const selection = window.getSelection();
            #             if (!selection || !selection.rangeCount) return null;
            #
            #             const range = selection.getRangeAt(0);
            #             let startContainer = range.startContainer;
            #             if (!startContainer) return null;
            #
            #             // 处理文本节点情况
            #             if (startContainer.nodeType === Node.TEXT_NODE) {
            #                 startContainer = startContainer.parentElement;
            #             }
            #
            #             if (!startContainer || !startContainer.closest) return null;
            #             const currentRow = startContainer.closest('.message-row');
            #             if (!currentRow) return null;
            #
            #             const rows = Array.from(document.querySelectorAll('.message-row'));
            #             const rowIndex = rows.indexOf(currentRow);
            #             const cursorPos = range.startOffset;
            #             const messageContent = currentRow.querySelector('.message-content');
            #
            #             return {
            #                 rowIndex: rowIndex,
            #                 cursorPos: cursorPos,
            #                 text: messageContent ? messageContent.textContent : ''
            #             };
            #         } catch (e) {
            #             console.error('JavaScript Error:', e);
            #             return null;
            #         }
            #     })();
            # """, lambda result: self.parent.log_message(f"Backspace事件上下文: {result}", 'DEBUG'))

            # 调用父对象的合并行方法
            self.parent.merge_lines(data)
        except Exception as e:
            self.parent.log_message(f"[ERROR] 处理Backspace键事件错误: {str(e)}", 'ERROR')
            self.parent.log_message(traceback.format_exc(), 'ERROR')


class ChapterDetailView(QWidget):
    content_changed = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self.parent = parent
        self.current_chapter_data = None
        self.current_content = []

        # 初始化Web通道
        self.channel = QWebChannel()
        self.bridge = None  # 延迟初始化

        self.init_ui()

    def log_message(self, message, level="INFO"):
        """记录日志消息

        Args:
            message: 日志消息
            level: 日志级别(DEBUG/INFO/WARNING/ERROR)
        """
        if hasattr(self.parent, 'log_message') and callable(self.parent.log_message):
            self.parent.log_message(message, level)

    def init_ui(self):
        """初始化UI组件"""
        super().__init__(self.parent)

        # 设置内容区域字体
        if hasattr(self, 'content_view'):
            self.content_view.setStyleSheet(
                f"font-size: {self.parent.CONTENT_FONT_SIZE}px;"
            )
        # 清除任何现有布局
        if hasattr(self, 'main_layout'):
            QWidget().setLayout(self.main_layout)

        self.main_layout = QVBoxLayout(self)
        self.main_layout.setContentsMargins(20, 20, 20, 20)
        self.main_layout.setSpacing(15)

        # 确保只添加必要的组件
        self.content_view = None

    def setup_view(self, chapter_data):
        """设置视图内容"""
        try:
            self.current_chapter_data = chapter_data
            self.current_content = chapter_data.get('chapter_content', [])

            # 验证parent参数
            if not hasattr(self.parent, 'log_message'):
                raise ValueError("无效的父对象，必须提供log_message方法")

            # 清除之前的控件
            self.cleanup()

            # 添加章节详情
            self.add_chapter_details(chapter_data)
            self.add_chapter_content(chapter_data)

            # 立即应用主题样式
            if hasattr(self.parent, 'apply_theme'):
                self.parent.apply_theme()
        except Exception as e:
            QMessageBox.warning(self, "错误", f"设置视图失败: {str(e)}")

    def cleanup(self):
        """清理资源"""
        try:
            # 清除之前的控件
            while self.main_layout.count() > 1:
                item = self.main_layout.takeAt(1)
                if item.widget():
                    # 如果是WebEngineView，确保正确清理
                    if isinstance(item.widget(), QWebEngineView):
                        view = item.widget()
                        # 清除页面内容
                        view.setHtml("")
                        # 停止加载
                        view.stop()
                        # 删除页面
                        if hasattr(self, 'web_page'):
                            self.web_page.deleteLater()
                    item.widget().deleteLater()

            # 重置状态
            if hasattr(self, 'content_view'):
                del self.content_view
            if hasattr(self, 'web_page'):
                del self.web_page
        except Exception as e:
            self.parent.log_message(f"清理资源时出错: {str(e)}")


    def add_chapter_details(self, chapter_data):
        """添加章节详情"""
        # 简化章节详情显示，只保留必要信息
        details_label = QLabel(
            f"章节: {chapter_data.get('chapter_name', '')} | "
            f"长度: {chapter_data.get('chapter_len', '')}"
        )
        self.main_layout.addWidget(details_label)

    def load_template(self):
        """加载HTML模板"""
        try:
            template_path = os.path.join(os.path.dirname(__file__), 'templates', 'chapter_content.html')
            with open(template_path, 'r', encoding='utf-8') as f:
                return f.read()
        except Exception as e:
            self.parent.log_message(f"加载模板失败: {str(e)}")
            return None

    def generate_content_rows(self, content):
        """生成内容行HTML"""
        rows = []
        for index, item in enumerate(content):

            # 如果item是字符串，使用默认值
            if isinstance(item, str):
                name = "旁白"
                text = item
                color = "white"
            else:
                # 如果item是字典，解析相应的字段
                name = item.get('name', '旁白')
                text = item.get('defaultText', '')
                color = item.get('color', 'white')

            rows.append(f"""
                <div class="message-row" id="{index}" style="line-height: 1.2;">
                    <div class="character-name" contenteditable="true" style="background-color: {color};">{name}</div>
                    <div class="message-content" style="background-color: {color};">{text}</div>
                </div>""")

        return '\n'.join(rows)

    def add_chapter_content(self, chapter_data):
        """添加章节内容"""
        self.content_view = QWebEngineView()

        # 创建自定义页面以处理JavaScript回调
        class WebEnginePage(QWebEnginePage):
            def __init__(self, parent=None):
                # 基本验证
                if parent is None:
                    raise ValueError("WebEnginePage必须传入有效的父对象")
                if not isinstance(parent, ChapterDetailView):
                    raise TypeError(f"父对象类型错误，期望ChapterDetailView，实际得到{type(parent)}")

                super().__init__(parent)
                self._parent = parent

                # 更灵活的父窗口链处理
                try:
                    # 尝试获取父窗口
                    if hasattr(self._parent, 'parent'):
                        if callable(self._parent.parent):
                            self._parent_parent = self._parent.parent()
                        else:
                            self._parent_parent = self._parent.parent
                            self._parent.log_message("ChapterDetailView的parent属性不是可调用方法，直接使用属性值",
                                                     'WARNING')
                    else:
                        self._parent_parent = None
                        self._parent.log_message("ChapterDetailView缺少parent属性", 'WARNING')

                    # 验证必要方法
                    if self._parent_parent is not None:
                        required_methods = ['log_message']
                        for method in required_methods:
                            if not hasattr(self._parent_parent, method):
                                self._parent.log_message(f"父窗口缺少方法: {method}", 'WARNING')
                except Exception as e:
                    self._parent.log_message(f"初始化{str(e)}", 'WARNING')
                    self._parent_parent = None

                # 记录parent.parent的详细信息
                self._parent.log_message(f"parent.parent类型: {type(self._parent.parent)}", 'DEBUG')
                self._parent.log_message(f"parent.parent值: {self._parent.parent}", 'DEBUG')

                # 严格验证父窗口链
                if not hasattr(self._parent, 'parent'):
                    raise AttributeError("ChapterDetailView必须设置有效的parent属性")
                if hasattr(self._parent, 'parent'):
                    self._parent_parent = self._parent.parent if not callable(
                        self._parent.parent) else self._parent.parent()
                else:
                    raise AttributeError("ChapterDetailView必须设置parent属性")

                if self._parent_parent is None:
                    raise ValueError("ChapterDetailView的parent()方法不能返回None")

                # 验证父窗口的必要方法
                required_methods = ['log_message']
                for method in required_methods:
                    if not hasattr(self._parent_parent, method):
                        raise AttributeError(f"父窗口必须实现{method}方法")

            def javaScriptConsoleMessage(self, level, message, line, source):
                # 安全检查
                if self._parent is None or self._parent_parent is None:
                    return

                # 将JavaScript级别映射为Python日志级别
                level_mapping = {
                    0: "DEBUG",
                    1: "INFO",
                    2: "WARNING",
                    3: "ERROR"
                }
                log_level = level_mapping.get(level, "INFO")

                if len(message) > 500 and ('<!DOCTYPE' in message or '<html>' in message):
                    return
                if '%3C' in message and '%3E' in message:
                    return

                if 'key' in message.lower() or 'enter' in message.lower() or 'backspace' in message.lower():
                    self._parent_parent.log_message(f"键盘事件: {message}", log_level)
                    self._parent_parent.log_message(f"  - 行号: {line}", log_level)

                    if 'enter' in message.lower():
                        try:
                            position_info = json.loads(message.split(':', 1)[1].strip())
                            self._parent.split_line(position_info)
                        except (json.JSONDecodeError, IndexError):
                            self._parent.log_message("警告: 解析Enter键位置信息失败", 'WARNING')
                    elif 'backspace' in message.lower():
                        position_info = json.loads(message.split(':', 1)[1].strip())
                        self._parent.merge_lines(position_info)
                    return
                self._parent_parent.log_message(f"键盘事件: {message}", log_level)
                self._parent_parent.log_message(f"{message}", log_level)
                if line:
                    self._parent_parent.log_message(f"  - 行号: {line}", log_level)

        # 确保传入有效的父对象
        self.web_page = WebEnginePage(self)
        self.content_view.setPage(self.web_page)

        # 初始化WebBridge实例
        self.bridge = WebBridge(self, self.web_page)
        self.channel.registerObject("handler", self.bridge)

        # 设置Web通道
        self.web_page.setWebChannel(self.channel)

        try:
            content = chapter_data.get('chapter_content', [])
            template = self.load_template()

            if template is None:
                raise Exception("无法加载HTML模板")

            content_rows = self.generate_content_rows(content)
            formatted_content = template.replace('{{content_rows}}', content_rows)

            self.content_view.setHtml(formatted_content)

        except Exception as e:
            error_html = f"""
            <html><body>
                <div style="color: red; padding: 20px;">内容解析错误: {str(e)}</div>
            </body></html>
            """
            self.content_view.setHtml(error_html)

        self.main_layout.addWidget(self.content_view, stretch=1)

    def handle_content_change(self, content):
        """处理内容变化"""
        try:
            self.current_content = content
            self.save_changes()
        except Exception as e:
            QMessageBox.warning(self, "错误", f"内容解析失败: {str(e)}")

    def save_changes(self):
        """保存修改"""
        if not self.current_chapter_data:
            return

        try:
            # 更新当前章节数据的内容
            self.current_chapter_data['chapter_content'] = self.current_content
            # 将新的章节内容保存到数据库中
            # 调用saveChapter接口保存数据
            import requests
            data = {
                'chapter_id': self.current_chapter_data.get('id'),
                'book_id': self.current_chapter_data.get('book_id'),
                'chapter_content': self.current_content
            }
            response = requests.post('http://127.0.0.1:5000/saveChapter', json=data)

            if response.status_code == 200:
                print("章节内容保存成功")
            else:
                print(f"保存章节内容失败: {response.text}")
                raise Exception(f"API调用失败: {response.text}")
            # 触发内容变化信号
            self.content_changed.emit()

            # 显示保存动画
            self.web_page.runJavaScript("""
                // 检查是否已存在保存提示元素
                if (!window.saveNotification) {
                    window.saveNotification = document.createElement('div');
                    window.saveNotification.style.cssText = `
                        position: fixed;
                        top: 20px;
                        right: 20px;
                        background-color: rgba(0, 128, 0, 0.8);
                        color: white;
                        padding: 10px 20px;
                        border-radius: 5px;
                        opacity: 0;
                        transition: opacity 0.3s ease-in-out;
                        z-index: 1000;
                    `;
                    document.body.appendChild(window.saveNotification);
                }
                
                // 更新内容并显示动画
                window.saveNotification.textContent = '已保存';
                setTimeout(() => {
                    window.saveNotification.style.opacity = '1';
                    setTimeout(() => {
                        window.saveNotification.style.opacity = '0';
                    }, 1500);
                }, 0);
            """)

            # 显示保存提示到日志
            self.parent.log_message(f"章节 {self.current_chapter_data.get('id', '')} 内容已修改")
        except Exception as e:
            QMessageBox.warning(self, "错误", f"保存失败: {str(e)}")

    def is_sentence_end(self, char):
        """判断字符是否为断句符号"""
        return char in ['.', '。', '!', '！', '?', '？', ';', '；', ':', '：', ',', '，', '、', '‘', '’', '“', '”', '…']

    def split_line(self, position_info):
        # 防抖处理：500ms内不重复执行
        if hasattr(self, '_last_split_time') and \
                time.time() - self._last_split_time < 0.5:
            return

        self._last_split_time = time.time()

        try:
            # 获取行索引和光标位置
            row_index = int(position_info.get('id'))
            cursor_pos = position_info.get('position')
            text = position_info.get('text', '')

            if row_index is None or cursor_pos is None:
                self.parent.log_message("无效的位置信息")
                return

            # 检查拆分点前后是否是断句符号
            need_confirm = True
            if cursor_pos > 0 and cursor_pos < len(text):
                char_before = text[cursor_pos - 1]
                if self.is_sentence_end(char_before):
                    need_confirm = False

            # 如果需要确认，显示确认对话框
            if need_confirm:
                msg_box = QMessageBox()
                msg_box.setWindowTitle("确认拆分")
                msg_box.setText(
                    "当前拆分点不是在断句符号后，确定要拆分吗？<div style='color:green'>PS：小编提醒，回车键可快捷确认</div>")
                msg_box.setTextFormat(Qt.RichText)
                msg_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
                msg_box.setDefaultButton(QMessageBox.Yes)
                reply = msg_box.exec_()
                if reply == QMessageBox.No:
                    return

            current_row = self.current_content[int(row_index)]

            # 分割文本
            text_before = text[:cursor_pos]
            text_after = text[cursor_pos:]

            # 创建新行，保持与原行相同的格式
            if isinstance(current_row, str):
                # 处理字符串类型：先删除原行再插入
                del self.current_content[row_index]
                self.current_content.insert(row_index, text_before)
                self.current_content.insert(row_index, text_after)
            else:
                # 处理字典类型：先深拷贝原字典
                import copy
                new_row = copy.deepcopy(current_row)
                current_row['defaultText'] = text_before
                new_row['defaultText'] = text_after
                self.current_content.insert(row_index + 1, new_row)

            # 更新UI
            self.refresh_content()

            # 保存更改
            self.save_changes()

        except Exception as e:
            self.parent.log_message(f"分割行错误: {str(e)}")
            QMessageBox.warning(self, "错误", f"分割行失败: {str(e)}")

    def merge_lines(self, position_info):
        """合并行"""
        try:
            # 获取当前行索引和光标位置
            # self.web_page.runJavaScript("""
            #     (function() {
            #         const selection = window.getSelection();
            #         if (!selection.rangeCount) return null;
            #
            #         const range = selection.getRangeAt(0);
            #         const startContainer = range.startContainer;
            #
            #         # 查找当前行
            #         let currentRow = startContainer.closest('.message-row');
            #         if (!currentRow) return null;
            #
            #         # 获取行索引
            #         let rows = Array.from(document.querySelectorAll('.message-row'));
            #         let rowIndex = rows.indexOf(currentRow);
            #
            #         # 获取光标在文本中的位置
            #         let messageContent = currentRow.querySelector('.message-content');
            #         let cursorPos = range.startOffset;
            #
            #         # 检查是否在行首
            #         if (cursorPos === 0 && rowIndex > 0) {
            #             return {
            #                 rowIndex: rowIndex,
            #                 prevRowIndex: rowIndex - 1,
            #                 text: messageContent.textContent
            #             };
            #         }
            #
            #         return null;
            #     })();
            # """, self.handle_merge_result)
            self.handle_merge_result(position_info)
        except Exception as e:
            self.parent.log_message(f"合并行错误: {str(e)}")
            QMessageBox.warning(self, "错误", f"合并行失败: {str(e)}")

    def handle_merge_result(self, result):
        """处理合并行的JavaScript回调结果"""
        if not result:
            return

        try:
            row_index = int(result.get('id'))
            prev_row_index = int(result.get('prevId'))
            # current_text = result.get('text', '')

            if row_index is None or prev_row_index is None:
                return

            # 获取前一行和当前行
            prev_row = self.current_content[prev_row_index]
            current_row = self.current_content[row_index]
            prev_text = prev_row.get('defaultText', '')
            current_text = current_row.get('defaultText', '')
            merged_text = prev_text + current_text
            prev_row['defaultText'] = merged_text

            # 设置光标到合并后的位置
            self.web_page.runJavaScript(f"""
                (function() {{
                    try {{
                        const rows = Array.from(document.querySelectorAll('.message-row'));
                        const prevRow = rows[{prev_row_index}];
                        if (!prevRow) return;
                        
                        const content = prevRow.querySelector('.message-content');
                        if (!content) return;
                        
                        // 创建新的range对象
                        const range = document.createRange();
                        const selection = window.getSelection();
                        
                        // 设置光标到文本末尾
                        range.setStart(content.firstChild, {len(prev_text)});
                        range.collapse(true);
                        
                        // 清除当前选择并添加新range
                        selection.removeAllRanges();
                        selection.addRange(range);
                    }} catch (e) {{
                        console.error('设置光标位置错误:', e);
                    }}
                }})();
            """)
            # 删除当前行
            self.current_content.pop(row_index)

            # 更新UI
            self.refresh_content()

            # 保存更改
            self.save_changes()

        except Exception as e:
            self.parent.log_message(f"处理合并行结果错误: {str(e)}")
            QMessageBox.warning(self, "错误", f"合并行失败: {str(e)}")

    def refresh_content(self):
        """刷新内容显示"""
        try:
            content_rows = self.generate_content_rows(self.current_content)
            self.web_page.runJavaScript(f"""
                // 检查是否已存在containers变量
                if (!window.contentContainers) {{
                    window.contentContainers = document.getElementsByClassName('content-container');
                }}
                
                // 更新内容
                if (window.contentContainers.length > 0) {{
                    window.contentContainers[0].innerHTML = `{content_rows}`;
                    console.log('内容更新成功');
                }} else {{
                    console.error('未找到content-container元素');
                }}
            """)
        except Exception as e:
            self.parent.log_message(f"刷新内容错误: {str(e)}")
            QMessageBox.warning(self, "错误", f"刷新内容失败: {str(e)}")

    def apply_theme(self):
        """应用当前主题样式"""
        if not hasattr(self.parent, 'current_theme'):
            return

        theme = StyleManager.get_theme(self.parent.current_theme)

        # 设置主窗口样式
        self.setStyleSheet(StyleManager.get_style("main_window", self.parent.current_theme))

        # 设置内容区域字体大小
        if hasattr(self, 'content_view') and self.content_view:
            self.content_view.setStyleSheet(
                f"font-size: {self.parent.content_font_size}px;"
            )

        # 设置日志框样式
        if hasattr(self, 'log_box') and self.log_box:
            text_color = theme['text']
            if self.parent.current_theme == 'light':
                text_color = '#333333'
            elif self.parent.current_theme == 'dark':
                text_color = '#e0e0e0'
            elif self.parent.current_theme == 'eye_care':
                text_color = '#3a3a3a'

            self.log_box.setStyleSheet(
                f"""
                QTextEdit {{
                    background-color: {theme['log']};
                    color: {text_color};
                    border: 1px solid {theme['text']};
                    font-size: {self.parent.default_font_size}px;
                    selection-background-color: {theme['button']};
                }}
                QTextEdit:hover {{
                    border: 1px solid {theme['button']};
                }}
                """
            )